﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using StyleMVVM.Data.Activation;
using StyleMVVM.DependencyInjection;
using StyleMVVM.DependencyInjection.Impl;

namespace StyleMVVM.MVC.DependencyInjection
{
	public class ImportFromHttpQueryStringAttribute : Attribute, IImportAttribute
	{
		public ImportFromHttpQueryStringAttribute()
		{
			Required = true;
		}

		public string ParameterName { get; set; }

		public bool Required { get; set; }

		public IImportAttributeInfo ProvideImportInfo(object memberInfo)
		{
			Type finalType = null;
			PropertyInfo propertyInfo = memberInfo as PropertyInfo;

			if (propertyInfo != null)
			{
				if (string.IsNullOrEmpty(ParameterName))
				{
					ParameterName = propertyInfo.Name;
				}

				finalType = propertyInfo.PropertyType;
			}
			else
			{
				ParameterInfo parameterInfo = memberInfo as ParameterInfo;

				if (parameterInfo != null)
				{
					finalType = parameterInfo.ParameterType;

					if (string.IsNullOrEmpty(ParameterName))
					{
						ParameterName = parameterInfo.Name;
					}
				}
			}

			return new ImportAttributeInfo
				       {
					       ImportName = "",
					       Required = Required,
					       Volatile = false,
					       ExportActivator = new Impl { ParameterName = ParameterName, FinalType = finalType }
				       };
		}

		private class Impl : IExportActivator
		{
			public string ParameterName { get; set; }

			public Type FinalType { get; set; }

			public IDependencyInjectionContainer Container { get; set; }

			public IActivationService ActivationService { get; set; }

			public object Activate(IInjectionContext injectionContext, object[] constructorParams)
			{
				string propertyString = HttpContext.Current.Request.QueryString[ParameterName];

				if (FinalType != typeof(string) && !string.IsNullOrEmpty(propertyString))
				{
					Type underlyingType = Nullable.GetUnderlyingType(FinalType);

					if (underlyingType != null)
					{
						return Convert.ChangeType(propertyString, underlyingType);
					}

					if (FinalType.IsValueType)
					{
						return Convert.ChangeType(propertyString, FinalType);
					}

					throw new ArgumentException("You can only import ValueTypes or Nullable Types");
				}

				return propertyString;
			}
		}
	}
}